package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.Product;
import cn.wolfcode.domain.SeckillProduct;
import cn.wolfcode.domain.SeckillProductVo;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.web.feign.ProductFeignApi;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lanxw
 */
@Service
public class SeckillProductServiceImpl implements ISeckillProductService {
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private ProductFeignApi productFeignApi;
    @Override
    public List<SeckillProductVo> queryByTime(Integer time) {
        //1.根据time查询秒杀商品表获取集合
        List<SeckillProduct> seckillProductList = seckillProductMapper.queryCurrentlySeckillProduct(time);
        //2.获取到商品ID集合.
        List<Long> ids = new ArrayList<>();
        for(SeckillProduct seckillProduct:seckillProductList){
            ids.add(seckillProduct.getProductId());
        }
        //3.进行远程调用获取商品的集合
        Result<List<Product>> result = productFeignApi.queryByIds(ids);
        //针对异常继续处理
        if(result==null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.PRODUCT_SERVER_ERROR);
        }
        List<Product> productList = result.getData();
        //先将List转成map，key=productId，value=Product对象
        Map<Long,Product> productMap = new HashMap<>();
        for(Product product:productList){
            productMap.put(product.getId(),product);
        }
        //4.将秒杀商品和商品数据进行关联，封装成SeckillProductVo
        List<SeckillProductVo> seckillProductVoList = new ArrayList<>();
        for(SeckillProduct seckillProduct:seckillProductList){
            SeckillProductVo vo = new SeckillProductVo();
            //将秒杀商品和商品数据进行关联
            Long productId = seckillProduct.getProductId();
            Product product = productMap.get(productId);
            BeanUtils.copyProperties(product,vo);
            BeanUtils.copyProperties(seckillProduct,vo);
            vo.setCurrentCount(seckillProduct.getStockCount());//当前商品的数量
            seckillProductVoList.add(vo);
        }
        //5.将集合返回
        return seckillProductVoList;
    }

    @Override
    public SeckillProductVo find(Long seckillId, Integer time) {
        //根据seckillId查询秒杀商品的数据
        SeckillProduct seckillProduct = seckillProductMapper.find(seckillId);
        List<Long> ids = new ArrayList<>();
        ids.add(seckillProduct.getProductId());
        //3.进行远程调用获取商品的集合
        Result<List<Product>> result = productFeignApi.queryByIds(ids);
        //针对异常继续处理
        if(result==null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.PRODUCT_SERVER_ERROR);
        }
        List<Product> productList = result.getData();
        Product product = productList.get(0);
        //把商品id获取出来，进行远程调用获取商品数据
        //将商品数据和秒杀商品数据进行合并，封装成Vo
        SeckillProductVo vo = new SeckillProductVo();
        BeanUtils.copyProperties(product,vo);
        BeanUtils.copyProperties(seckillProduct,vo);
        vo.setCurrentCount(seckillProduct.getStockCount());//当前商品的数量
        return vo;
    }

    @Override
    public int decrStockCount(Long seckillId) {
        return seckillProductMapper.decrStock(seckillId);
    }

    @Override
    public List<SeckillProductVo> queryByTimeFromCache(Integer time) {
        String seckillProductKey = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(String.valueOf(time));
        List<Object> values = redisTemplate.opsForHash().values(seckillProductKey);
        List<SeckillProductVo> voList = new ArrayList<>();
        for(Object object:values){
            voList.add(JSON.parseObject((String) object,SeckillProductVo.class));
        }
        return voList;
    }

    @Override
    public SeckillProductVo findFromCache(Long seckillId, Integer time) {
        String seckillProductKey = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(String.valueOf(time));
        String objStr = (String) redisTemplate.opsForHash().get(seckillProductKey, String.valueOf(seckillId));
        return JSON.parseObject(objStr,SeckillProductVo.class);
    }

    @Override
    public void syncStockCountToRedis(Integer time, Long seckillId) {
        int stockCount = seckillProductMapper.getStockCount(seckillId);
        if(stockCount>0){
            String stockCountKey = SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(String.valueOf(time));
            redisTemplate.opsForHash().put(stockCountKey,String.valueOf(seckillId),String.valueOf(stockCount));
        }
    }

    @Override
    public void incrStockCount(Long seckillId) {
        seckillProductMapper.incrStock(seckillId);
    }
}
